package org.epidroid.epidroid.ratp.ui;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.epidroid.epidroid.R;
import org.epidroid.epidroid.ratp.ui.DataHandler.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class RatpUi extends Activity {
	DataRetrieve retriever = null;
	Map<Integer, RequestData[]> listViewIdentifiers;
	Map<String, Integer> listIdIdentifiers;
	HashMap<Integer, CheckBox> listCheckBoxId;
	SharedPreferences sharedPref = null;

	Integer[] bus = {R.string.bus47, R.string.bus131vj, R.string.bus131kb, R.string.bus125, R.string.bus185};
	Integer[] metros = {R.string.mkremlinbicetre, R.string.mporteditalie, R.string.mvillejuifll};
	Integer[] trams = {R.string.tporteditalie};
	
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.ratp_ui);

		listCheckBoxId = new HashMap<Integer, CheckBox>();
//		listCheckBoxId.put(R.id.lvbus47, R.id.checkb47);
//		listCheckBoxId.put(R.id.lvbus131kb, R.id.checkb131kb);
//		listCheckBoxId.put(R.id.lvbus131vj, R.id.checkb131vj);
//		listCheckBoxId.put(R.id.lvbus125, R.id.checkb125);
//		listCheckBoxId.put(R.id.lvbus185, R.id.checkb185);
//		listCheckBoxId.put(R.id.lvmkremlinbicetre, R.id.checkmkb);
//		listCheckBoxId.put(R.id.lvmporteditalie, R.id.checkbmpdit);
//		listCheckBoxId.put(R.id.lvmvillejuifll, R.id.checkmvjll);
//		listCheckBoxId.put(R.id.lvtporteditalie, R.id.checktpdit);
//
		listViewIdentifiers = new Hashtable<Integer, RequestData[]>();
		listIdIdentifiers = new Hashtable<String, Integer>();
		
		RequestData[] b47 = new RequestData[1];
		b47[0] = new RequestData(1, 499, 12948);
		listViewIdentifiers.put(R.string.bus47, b47);
		listIdIdentifiers.put(getString(R.string.bus47), R.string.bus47);


		RequestData[] b131k = new RequestData[1];
		b131k[0] = new RequestData(1, 127, 2628);
		listViewIdentifiers.put(R.string.bus131kb, b131k);
		listIdIdentifiers.put(getString(R.string.bus131kb), R.string.bus131kb);

		RequestData[] b131v = new RequestData[1];
		b131v[0] = new RequestData(1, 127, 2619);
		listViewIdentifiers.put(R.string.bus131vj, b131v);
		listIdIdentifiers.put(getString(R.string.bus131vj), R.string.bus131vj);

		RequestData[] b125 = new RequestData[1];
		b125[0] = new RequestData(1, 117, 2369);
		listViewIdentifiers.put(R.string.bus125, b125);
		listIdIdentifiers.put(getString(R.string.bus125), R.string.bus125);

		RequestData[] b185 = new RequestData[1];
		b185[0] = new RequestData(1, 225, 5481);
		listViewIdentifiers.put(R.string.bus185, b185);
		listIdIdentifiers.put(getString(R.string.bus185), R.string.bus185);
		
		RequestData[] m7kb = new RequestData[2];
		m7kb[0] = new RequestData(2, 31, 498);
		m7kb[1] = new RequestData(2, 32, 535);
		listViewIdentifiers.put(R.string.mkremlinbicetre, m7kb);
		listIdIdentifiers.put(getString(R.string.mkremlinbicetre), R.string.mkremlinbicetre);

		RequestData[] m7vjll = new RequestData[2];
		m7vjll[0] = new RequestData(2, 31, 522);
		m7vjll[1] = new RequestData(2, 32, 558);
		listViewIdentifiers.put(R.string.mvillejuifll, m7vjll);
		listIdIdentifiers.put(getString(R.string.mvillejuifll), R.string.mvillejuifll);

		RequestData[] m7pdit = new RequestData[2];
		m7pdit[0] = new RequestData(2, 31, 512);
		m7pdit[1] = new RequestData(2, 32, 549);
		listViewIdentifiers.put(R.string.mporteditalie, m7pdit);
		listIdIdentifiers.put(getString(R.string.mporteditalie), R.string.mporteditalie);

		RequestData[] t3 = new RequestData[2];
		t3[0] = new RequestData(6, 67, 1006);
		t3[1] = new RequestData(6, 66, 1007);
		listViewIdentifiers.put(R.string.tporteditalie, t3);
		listIdIdentifiers.put(getString(R.string.tporteditalie), R.string.tporteditalie);
	}

	private void loadUI(Integer[] elts, Integer eltString) {
		sharedPref = getSharedPreferences("ratpPref", Context.MODE_PRIVATE);
		LayoutInflater inflater = getLayoutInflater();
		LinearLayout mainList = (LinearLayout) findViewById(R.id.ratplist);

		Boolean present = false;
		LinearLayout ll = null;
		for (Integer b : elts) {
			if (sharedPref.getBoolean(b.toString(), true)) {
				if (!present) {
					present = true;
					View row = inflater.inflate(R.layout.ratp_transport_row, mainList, false);
					((TextView) row.findViewById(R.id.ratpTextViewTransport)).setText(eltString);
					mainList.addView(row);
					ll = (LinearLayout) row.findViewById(R.id.ratp_transport_ll);
				}
				View row = inflater.inflate(R.layout.ratp_row, mainList, false);
				((TextView) row.findViewById(R.id.ratpRowTextView)).setText(getString(b));
				((CheckBox) row.findViewById(R.id.ratpRowCheckBox)).setChecked(true);
				((ListView) row.findViewById(R.id.ratpRowListView)).setAdapter(new TimeAdapter());
				((ListView) row.findViewById(R.id.ratpRowListView)).setId(b);
				ll.addView(row);
			}
		}
	}
	
	public void onResume() {
		super.onResume();

		loadUI(bus, R.string.bus);
		loadUI(metros, R.string.metro);
		loadUI(trams, R.string.tramway);
		
//		((CheckBox) findViewById(R.id.checkb47)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvbus47).toString(), true));
//		((CheckBox) findViewById(R.id.checkb131kb)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvbus131kb).toString(), true));
//		((CheckBox) findViewById(R.id.checkb131vj)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvbus131vj).toString(), true));
//		((CheckBox) findViewById(R.id.checkb125)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvbus125).toString(), true));
//		((CheckBox) findViewById(R.id.checkb185)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvbus185).toString(), true));
//		((CheckBox) findViewById(R.id.checkmkb))
//				.setChecked(sharedPref.getBoolean(
//						((Integer) R.id.lvmkremlinbicetre).toString(), true));
//		((CheckBox) findViewById(R.id.checkbmpdit)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvmporteditalie).toString(), true));
//		((CheckBox) findViewById(R.id.checkmvjll)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvmvillejuifll).toString(), true));
//		((CheckBox) findViewById(R.id.checktpdit)).setChecked(sharedPref
//				.getBoolean(((Integer) R.id.lvtporteditalie).toString(), true));

		HashMap<Integer, RequestData[]> list = new HashMap<Integer, RequestData[]>();
		for (Entry<Integer, RequestData[]> entry : listViewIdentifiers
				.entrySet()) {
			Log.d("Epidroid", entry.getKey().toString());
			if (sharedPref.getBoolean(entry.getKey().toString(), true)) {
				list.put(entry.getKey(), entry.getValue());
			}
		}
		Set<Entry<Integer, RequestData[]>> datas = list.entrySet();
		retriever = new DataRetrieve(datas);
		retriever.execute();
	}

	public void onPause() {
		super.onPause();
//		for (Entry<Integer, RequestData[]> entry : listViewIdentifiers
//				.entrySet()) {
//			ListView ll = (ListView) findViewById(entry.getKey());
//			((TimeAdapter) ll.getAdapter()).notifyDataSetInvalidated();
//			((TimeAdapter) ll.getAdapter()).clear();
//			((TimeAdapter) ll.getAdapter()).notifyDataSetChanged();
//		}
		sharedPref = null;
	}

	private void updateDisplay(Integer key, Element elt) {
		ListView ll = (ListView) findViewById(key);

		// LinearLayout row = (LinearLayout) inflater.inflate(R.layout.ratp_raw,
		// ll, false);
		// TextView direction = (TextView) row.findViewById(R.id.direction);
		// TextView waitingTime = (TextView)
		// row.findViewById(R.id.waiting_time);

		if (elt.texts[0] != null && elt.texts[2] != null) {
			((TimeAdapter) ll.getAdapter()).notifyDataSetInvalidated();
			((TimeAdapter) ll.getAdapter()).add(elt.texts[0], elt.texts[2]);
			((TimeAdapter) ll.getAdapter()).notifyDataSetChanged();
			LayoutParams params = ll.getLayoutParams();
			params.height = 30 * ((TimeAdapter) ll.getAdapter()).getCount();
			ll.setLayoutParams(params);
			LinearLayout globalLayout = (LinearLayout) findViewById(R.id.ratplist);
			globalLayout.setScrollContainer(true);
			globalLayout.setVerticalScrollBarEnabled(true);

		}
	}

	public class TimeAdapter extends BaseAdapter {
		ArrayList<String> directions;
		ArrayList<String> waitingTime;

		public TimeAdapter() {
			directions = new ArrayList<String>();
			waitingTime = new ArrayList<String>();
		}

		public void add(String direction, String waitTime) {
			directions.add(direction);
			waitingTime.add(waitTime);
		}

		public void clear() {
			directions.clear();
			waitingTime.clear();
		}

		@Override
		public int getCount() {
			return directions.size();
		}

		@Override
		public Object getItem(int position) {
			return null;
		}

		@Override
		public long getItemId(int position) {
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			LinearLayout row = null;
			LayoutInflater inflater = getLayoutInflater();
			row = (LinearLayout) inflater.inflate(R.layout.ratp_raw, null,
					false);
			TextView direction = (TextView) row.findViewById(R.id.direction);
			TextView waiting = (TextView) row.findViewById(R.id.waiting_time);

			direction.setText(directions.get(position));
			waiting.setText(waitingTime.get(position));
			return row;
		}

	}

	public class DataRetrieve extends AsyncTask<Void, DataHandler, Void> {
		public Set<Entry<Integer, RequestData[]>> _requests;
		ProgressDialog alert;

		public DataRetrieve(Set<Entry<Integer, RequestData[]>> requests) {
			_requests = requests;
		}

		@Override
		protected void onPreExecute() {
			alert = ProgressDialog.show(RatpUi.this,
					RatpUi.this.getText(R.string.loading),
					"Retrieving RATP data", true, true, new OnCancelListener() {
						@Override
						public void onCancel(DialogInterface dialog) {
							retriever.cancel(true);
						}
					});
		}

		@Override
		protected Void doInBackground(Void... params) {
			for (Entry<Integer, RequestData[]> entry : _requests) {
				for (RequestData data : entry.getValue()) {
					if (isCancelled()) {
						return null;
					}
					HttpGet request = new HttpGet(
							"http://ratp-bridge.fabernovel.com/ratp.schedule?reseau="
									+ data.reseau + "&direction="
									+ data.direction + "&station="
									+ data.station + "&");
					DefaultHttpClient client_ = getHttpClient();
					try {
						HttpResponse response = client_.execute(request);
						HttpEntity entity = response.getEntity();
						String xml = EntityUtils.toString(entity);
						XMLReader reader = initParser();
						DataHandler handler = new DataHandler(entry.getKey());
						// assign our handler
						reader.setContentHandler(handler);
						// perform the synchronous parse
						reader.parse(new InputSource(new StringReader(xml)));

						// retrieve the data
						publishProgress(handler);
					} catch (ClientProtocolException e) {
						Log.e("DEBUG",
								"ClientProtocolException : " + e.getMessage());
						request.abort();
						RatpUi.this.displayError();
					} catch (IOException e) {
						Log.e("DEBUG", "IOException " + e.getMessage());
						request.abort();
						RatpUi.this.displayError();
					} catch (ParserConfigurationException e) {
						Log.e("EPIDROID.RATP", "ParserConfiguration Exception "
								+ e.getLocalizedMessage());
						request.abort();
						RatpUi.this.displayError();
					} catch (SAXException e) {
						Log.e("EPIDROID.RATP",
								"SAXException " + e.getLocalizedMessage());
						request.abort();
						RatpUi.this.displayError();
					}
				}
			}
			return null;
		}

		protected void onProgressUpdate(DataHandler... objects) {
			for (DataHandler handler : objects) {
				for (Element elt : handler.elements) {
					updateDisplay(handler.key_, elt);
				}
			}
		}

		protected void onCancelled(Void result) {
			retriever = null;
		}

		protected void onPostExecute(Void result) {
			// updateDisplay();
			retriever = null;
			alert.dismiss();
		}

		private DefaultHttpClient getHttpClient() {
			HttpParams httpParameters = new BasicHttpParams();
			HttpConnectionParams.setConnectionTimeout(httpParameters, 30000);
			HttpConnectionParams.setSoTimeout(httpParameters, 30000);
			DefaultHttpClient client_ = new DefaultHttpClient(httpParameters);

			return client_;
		}

		private XMLReader initParser() throws ParserConfigurationException,
				SAXException {
			SAXParserFactory factory = SAXParserFactory.newInstance();
			// create a parser
			SAXParser parser = factory.newSAXParser();
			// create the reader (scanner)
			XMLReader reader = parser.getXMLReader();
			return reader;
		}
	}

	public void showToast(String content) {
		Toast toast = Toast.makeText(getApplicationContext(), content,
				Toast.LENGTH_SHORT);
		toast.show();
	}

	private void displayError() {
		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				showToast("An error occured while retrieving the data from the server!");
			}
		});
	}

	public void ratpRowRefresh(View v) {
		Integer key = listIdIdentifiers.get(((TextView) ((LinearLayout) v.getParent()).findViewById(R.id.ratpRowTextView)).getText());

		ListView ll = (ListView) ((View) v.getParent().getParent()).findViewById(key);

		((TimeAdapter) ll.getAdapter()).notifyDataSetInvalidated();
		((TimeAdapter) ll.getAdapter()).clear();
		((TimeAdapter) ll.getAdapter()).notifyDataSetChanged();


		Map<Integer, RequestData[]> map = new Hashtable<Integer, RequestData[]>();
		map.put(key, listViewIdentifiers.get(key));
		retriever = new DataRetrieve(map.entrySet());
		retriever.execute();
	}

	public void onCheckedChange(View v) {
		Integer key = listIdIdentifiers.get(((TextView) ((LinearLayout) v.getParent()).findViewById(R.id.ratpRowTextView)).getText());

		SharedPreferences.Editor editor = sharedPref.edit();
		editor.putBoolean(key.toString(), false);
		editor.commit();
		
		LinearLayout ll = ((LinearLayout) v.getParent().getParent().getParent());
		ll.removeView((View) v.getParent().getParent());
		if (ll.getChildCount() == 1) {
			LinearLayout topll = (LinearLayout) ll.getParent();
			topll.removeView(ll);
		}
	}
	
	private ArrayList<Integer> checkedItems;
	
	private void addElements (LinearLayout checkboxLayout, Integer[] ids) {
		LayoutInflater inflater = getLayoutInflater();

		for (final Integer id : ids) {
			if (!sharedPref.getBoolean(id.toString(), true)) {
				View view = inflater.inflate(R.layout.ratp_select_row, null);
				((TextView) view.findViewById(R.id.textView)).setText(id);
				((CheckBox) view.findViewById(R.id.checkBox)).setOnClickListener(null);
				((CheckBox) view.findViewById(R.id.checkBox)).setOnCheckedChangeListener(new OnCheckedChangeListener() {
					
					@Override
					public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
						if (isChecked)
							checkedItems.add(id);
						else
							checkedItems.remove(id);
					}
				});
				checkboxLayout.addView(view);
			}
		}
	}
	
	public void showDialogHidden(View v) {
		String longMessage = getString(R.string.choose_favorites);

		final LayoutInflater inflater = getLayoutInflater();
		final View mainView = inflater.inflate(R.layout.ratp_select, null);
		final LinearLayout checkboxLayout = (LinearLayout) mainView.findViewById(R.id.ratp_select_ll);
		
		checkedItems = new ArrayList<Integer>();
		
		addElements(checkboxLayout, bus);
		addElements(checkboxLayout, metros);
		addElements(checkboxLayout, trams);

		AlertDialog.Builder builder = new AlertDialog.Builder(this)
		.setTitle(longMessage)
		.setView(mainView)
		.setPositiveButton(R.string.add,
		        new DialogInterface.OnClickListener() {
		        public void onClick(DialogInterface dialog, int which) {
		    		SharedPreferences.Editor editor = sharedPref.edit();
		    		LinearLayout mainList = (LinearLayout) findViewById(R.id.ratplist);

					View row_ = inflater.inflate(R.layout.ratp_transport_row, mainList, false);
					((TextView) row_.findViewById(R.id.ratpTextViewTransport)).setText(R.string.recentlyadded);
					mainList.addView(row_);
					LinearLayout ll = (LinearLayout) row_.findViewById(R.id.ratp_transport_ll);
					
					Map<Integer, RequestData[]> map = new Hashtable<Integer, RequestData[]>();
					
		        	for (Integer id : checkedItems) {
		        		editor.putBoolean(id.toString(), true);
		        		
		        		View row = inflater.inflate(R.layout.ratp_row, mainList, false);
						((TextView) row.findViewById(R.id.ratpRowTextView)).setText(getString(id));
						((CheckBox) row.findViewById(R.id.ratpRowCheckBox)).setChecked(true);
						((ListView) row.findViewById(R.id.ratpRowListView)).setAdapter(new TimeAdapter());
						((ListView) row.findViewById(R.id.ratpRowListView)).setId(id);
						ll.addView(row);
		        		
						map.put(id, listViewIdentifiers.get(id));
		        	}
		        	editor.commit();
		        	retriever = new DataRetrieve(map.entrySet());
		        	retriever.execute();
		        }
		})
		.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
			}
		});

		AlertDialog dialog = builder.create();
		dialog.show();
	}
}
